Meilisearch JavaScript
⚡ The Meilisearch API client written for JavaScript
Meilisearch JavaScript is the Meilisearch API client for JavaScript developers.
Meilisearch is an open-source search engine. Learn more about Meilisearch.
Table of Contents
📖 Documentation
This readme contains all the documentation you need to start using this Meilisearch SDK.
For general information on how to use Meilisearch—such as our API reference, tutorials, guides, and in-depth articles—refer to our main documentation website.
⚡ Supercharge your Meilisearch experience
Say goodbye to server deployment and manual updates with Meilisearch Cloud. Get started with a 14-day free trial! No credit card required.
🔧 Installation
We recommend installing meilisearch-js
in your project with your package manager of choice.
npm install meilisearch
meilisearch-js
officially supports node
versions >= 14 and <= 18.
Instead of using a package manager, you may also import the library directly into your HTML via a CDN.
Run Meilisearch
To use one of our SDKs, you must first have a running Meilisearch instance. Consult our documentation for instructions on how to download and launch Meilisearch.
Import
After installing meilisearch-js
, you must import it into your application. There are many ways of doing that depending on your development environment.
import
syntax
Usage in an ES module environment:
import { MeiliSearch } from 'meilisearch'
const client = new MeiliSearch({
host: 'http://127.0.0.1:7700',
apiKey: 'masterKey',
})
<script>
tag
Usage in an HTML (or alike) file:
<script src='https://cdn.jsdelivr.net/npm/meilisearch@latest/dist/bundles/meilisearch.umd.js'></script>
<script>
const client = new MeiliSearch({
host: 'http://127.0.0.1:7700',
apiKey: 'masterKey',
})
</script>
require
syntax
Usage in a back-end node.js or another environment supporting CommonJS modules:
const { MeiliSearch } = require('meilisearch')
const client = new MeiliSearch({
host: 'http://127.0.0.1:7700',
apiKey: 'masterKey',
})
React Native
To use meilisearch-js
with React Native, you must also install react-native-url-polyfill.
Deno
Usage in a Deno environment:
import { MeiliSearch } from "https://esm.sh/meilisearch"
const client = new MeiliSearch({
host: 'http://127.0.0.1:7700',
apiKey: 'masterKey',
})
🎬 Getting started
Add documents
const { MeiliSearch } = require('meilisearch')
import { MeiliSearch } from 'meilisearch'
;(async () => {
const client = new MeiliSearch({
host: 'http://127.0.0.1:7700',
apiKey: 'masterKey',
})
const index = client.index('movies')
const documents = [
{ id: 1, title: 'Carol', genres: ['Romance', 'Drama'] },
{ id: 2, title: 'Wonder Woman', genres: ['Action', 'Adventure'] },
{ id: 3, title: 'Life of Pi', genres: ['Adventure', 'Drama'] },
{ id: 4, title: 'Mad Max: Fury Road', genres: ['Adventure', 'Science Fiction'] },
{ id: 5, title: 'Moana', genres: ['Fantasy', 'Action']},
{ id: 6, title: 'Philadelphia', genres: ['Drama'] },
]
let response = await index.addDocuments(documents)
console.log(response)
})()
Tasks such as document addition always return a unique identifier. You can use this identifier taskUid
to check the status (enqueued
, canceled
, processing
, succeeded
or failed
) of a task.
Basic search
const search = await index.search('philoudelphia')
console.log(search)
Output:
{
"hits": [
{
"id": "6",
"title": "Philadelphia",
"genres": ["Drama"]
}
],
"offset": 0,
"limit": 20,
"estimatedTotalHits": 1,
"processingTimeMs": 1,
"query": "philoudelphia"
}
Using search parameters
meilisearch-js
supports all search parameters described in our main documentation website.
await index.search(
'wonder',
{
attributesToHighlight: ['*']
}
)
{
"hits": [
{
"id": 2,
"title": "Wonder Woman",
"genres": ["Action", "Adventure"],
"_formatted": {
"id": "2",
"title": "<em>Wonder</em> Woman",
"genres": ["Action", "Adventure"]
}
}
],
"offset": 0,
"limit": 20,
"estimatedTotalHits": 1,
"processingTimeMs": 0,
"query": "wonder"
}
Custom search with filters
To enable filtering, you must first add your attributes to the filterableAttributes
index setting.
await index.updateFilterableAttributes([
'id',
'genres'
])
You only need to perform this operation once per index.
Note that Meilisearch rebuilds your index whenever you update filterableAttributes
. Depending on the size of your dataset, this might take considerable time. You can track the process using the tasks API).
After you configured filterableAttributes
, you can use the filter
search parameter to refine your search:
await index.search(
'wonder',
{
filter: ['id > 1 AND genres = Action']
}
)
{
"hits": [
{
"id": 2,
"title": "Wonder Woman",
"genres": ["Action","Adventure"]
}
],
"offset": 0,
"limit": 20,
"estimatedTotalHits": 1,
"processingTimeMs": 0,
"query": "wonder"
}
Placeholder search
Placeholder search makes it possible to receive hits based on your parameters without having any query (q
). For example, in a movies database you can run an empty query to receive all results filtered by genre
.
await index.search(
'',
{
filter: ['genres = fantasy'],
facets: ['genres']
}
)
{
"hits": [
{
"id": 2,
"title": "Wonder Woman",
"genres": ["Action","Adventure"]
},
{
"id": 5,
"title": "Moana",
"genres": ["Fantasy","Action"]
}
],
"offset": 0,
"limit": 20,
"estimatedTotalHits": 2,
"processingTimeMs": 0,
"query": "",
"facetDistribution": {
"genres": {
"Action": 2,
"Fantasy": 1,
"Adventure": 1
}
}
}
Note that to enable faceted search on your dataset you need to add genres
to the filterableAttributes
index setting. For more information on filtering and faceting, consult our documentation settings.
Abortable search
You can abort a pending search request by providing an AbortSignal to the request.
const controller = new AbortController()
index
.search('wonder', {}, {
signal: controller.signal,
})
.then((response) => {
})
.catch((e) => {
})
controller.abort()
Using Meilisearch behind a proxy
Custom request config
You can provide a custom request configuration. for example, with custom headers.
const client: MeiliSearch = new MeiliSearch({
host: 'http://localhost:3000/api/meilisearch/proxy',
requestConfig: {
headers: {
Authorization: AUTH_TOKEN
},
credentials: 'include'
}
})
Custom http client
You can use your own HTTP client, for example, with axios
.
const client: MeiliSearch = new MeiliSearch({
host: 'http://localhost:3000/api/meilisearch/proxy',
httpClient: async (url, opts) => {
const response = await $axios.request({
url,
data: opts?.body,
headers: opts?.headers,
method: (opts?.method?.toLocaleUpperCase() as Method) ?? 'GET'
})
return response.data
}
})
🤖 Compatibility with Meilisearch
This package guarantees compatibility with version v1.x of Meilisearch, but some features may not be present. Please check the issues for more info.
💡 Learn more
The following sections in our main documentation website may interest you:
This repository also contains more examples.
⚙️ Contributing
We welcome all contributions, big and small! If you want to know more about this SDK's development workflow or want to contribute to the repo, please visit our contributing guidelines for detailed instructions.
📜 API resources
Search
client.index<T>('xxx').search(query: string, options: SearchParams = {}, config?: Partial<Request>): Promise<SearchResponse<T>>
client.index<T>('xxx').searchGet(query: string, options: SearchParams = {}, config?: Partial<Request>): Promise<SearchResponse<T>>
Multi Search
client.multiSearch(queries?: MultiSearchParams, config?: Partial<Request>): Promise<Promise<MultiSearchResponse<T>>>
multiSearch
uses the POST
method when performing its request to Meilisearch.
Search For Facet Values
client.index<T>('myIndex').searchForFacetValues(params: SearchForFacetValuesParams, config?: Partial<Request>): Promise<SearchForFacetValuesResponse>
Documents
client.index('myIndex').addDocuments(documents: Document<T>[]): Promise<EnqueuedTask>
client.index('myIndex').addDocumentsFromString(documents: string, contentType: ContentType, queryParams: RawDocumentAdditionOptions): Promise<EnqueuedTask>
client.index('myIndex').addDocumentsInBatches(documents: Document<T>[], batchSize = 1000): Promise<EnqueuedTask[]>
client.index('myIndex').updateDocuments(documents: Array<Document<Partial<T>>>): Promise<EnqueuedTask>
client.index('myIndex').updateDocumentsFromString(documents: string, contentType: ContentType, queryParams: RawDocumentAdditionOptions): Promise<EnqueuedTask>
client.index('myIndex').updateDocumentsInBatches(documents: Array<Document<Partial<T>>>, batchSize = 1000): Promise<EnqueuedTask[]>
client.index.getDocuments(parameters: DocumentsQuery = {}): Promise<DocumentsResults<T>>>
client.index('myIndex').getDocument(documentId: string): Promise<Document<T>>
client.index('myIndex').deleteDocument(documentId: string | number): Promise<EnqueuedTask>
client.index('myIndex').deleteDocuments(params: DocumentsDeletionQuery | DocumentsIds): Promise<EnqueuedTask>
client.index('myIndex').deleteAllDocuments(): Promise<Types.EnqueuedTask>
Tasks
client.getTasks(parameters: TasksQuery): Promise<TasksResults>
client.getTask(uid: number): Promise<Task>
client.deleteTasks(parameters: DeleteTasksQuery = {}): Promise<EnqueuedTask>
client.cancelTasks(parameters: CancelTasksQuery = {}): Promise<EnqueuedTask>
client.index('myIndex').getTasks(parameters: TasksQuery): Promise<TasksResults>
client.index('myIndex').getTask(uid: number): Promise<Task>
Wait for one task
Using the client
client.waitForTask(uid: number, { timeOutMs?: number, intervalMs?: number }): Promise<Task>
Using the index
client.index('myIndex').waitForTask(uid: number, { timeOutMs?: number, intervalMs?: number }): Promise<Task>
Wait for multiple tasks
Using the client
client.waitForTasks(uids: number[], { timeOutMs?: number, intervalMs?: number }): Promise<Task[]>
Using the index
client.index('myIndex').waitForTasks(uids: number[], { timeOutMs?: number, intervalMs?: number }): Promise<Task[]>
Indexes
client.getIndexes(parameters: IndexesQuery): Promise<IndexesResults<Index[]>>
client.getRawIndexes(parameters: IndexesQuery): Promise<IndexesResults<IndexObject[]>>
client.createIndex<T>(uid: string, options?: IndexOptions): Promise<EnqueuedTask>
Create a local reference to an index
client.index<T>(uid: string): Index<T>
client.getIndex<T>(uid: string): Promise<Index<T>>
client.getRawIndex(uid: string): Promise<IndexObject>
client.index('myIndex').getRawInfo(): Promise<IndexObject>
Using the client
client.updateIndex(uid: string, options: IndexOptions): Promise<EnqueuedTask>
Using the index object
client.index('myIndex').update(data: IndexOptions): Promise<EnqueuedTask>
Using the client
client.deleteIndex(uid): Promise<void>
Using the index object
client.index('myIndex').delete(): Promise<void>
client.index('myIndex').getStats(): Promise<IndexStats>
Return Index instance with updated information
client.index('myIndex').fetchInfo(): Promise<Index>
Get Primary Key of an Index
client.index('myIndex').fetchPrimaryKey(): Promise<string | undefined>
Swap two indexes
client.swapIndexes(params: SwapIndexesParams): Promise<EnqueuedTask>
Settings
client.index('myIndex').getSettings(): Promise<Settings>
client.index('myIndex').updateSettings(settings: Settings): Promise<EnqueuedTask>
client.index('myIndex').resetSettings(): Promise<EnqueuedTask>
client.index('myIndex').getPagination(): Promise<PaginationSettings>
client.index('myIndex').updatePagination(pagination: PaginationSettings): Promise<EnqueuedTask>
client.index('myIndex').resetPagination(): Promise<EnqueuedTask>
Synonyms
client.index('myIndex').getSynonyms(): Promise<Synonyms>
client.index('myIndex').updateSynonyms(synonyms: Synonyms): Promise<EnqueuedTask>
client.index('myIndex').resetSynonyms(): Promise<EnqueuedTask>
Stop words
client.index('myIndex').getStopWords(): Promise<string[]>
client.index('myIndex').updateStopWords(stopWords: string[] | null ): Promise<EnqueuedTask>
client.index('myIndex').resetStopWords(): Promise<EnqueuedTask>
Ranking rules
client.index('myIndex').getRankingRules(): Promise<string[]>
client.index('myIndex').updateRankingRules(rankingRules: string[] | null): Promise<EnqueuedTask>
client.index('myIndex').resetRankingRules(): Promise<EnqueuedTask>
Distinct Attribute
client.index('myIndex').getDistinctAttribute(): Promise<string | void>
client.index('myIndex').updateDistinctAttribute(distinctAttribute: string | null): Promise<EnqueuedTask>
client.index('myIndex').resetDistinctAttribute(): Promise<EnqueuedTask>
Searchable attributes
client.index('myIndex').getSearchableAttributes(): Promise<string[]>
client.index('myIndex').updateSearchableAttributes(searchableAttributes: string[] | null): Promise<EnqueuedTask>
client.index('myIndex').resetSearchableAttributes(): Promise<EnqueuedTask>
Displayed attributes
client.index('myIndex').getDisplayedAttributes(): Promise<string[]>
client.index('myIndex').updateDisplayedAttributes(displayedAttributes: string[] | null): Promise<EnqueuedTask>
client.index('myIndex').resetDisplayedAttributes(): Promise<EnqueuedTask>
Filterable attributes
client.index('myIndex').getFilterableAttributes(): Promise<string[]>
client.index('myIndex').updateFilterableAttributes(filterableAttributes: string[] | null): Promise<EnqueuedTask>
client.index('myIndex').resetFilterableAttributes(): Promise<EnqueuedTask>
Sortable attributes
client.index('myIndex').getSortableAttributes(): Promise<string[]>
client.index('myIndex').updateSortableAttributes(sortableAttributes: string[] | null): Promise<EnqueuedTask>
client.index('myIndex').resetSortableAttributes(): Promise<EnqueuedTask>
Faceting
client.index('myIndex').getFaceting(): Promise<Faceting>
client.index('myIndex').updateFaceting(faceting: Faceting): Promise<EnqueuedTask>
client.index('myIndex').resetFaceting(): Promise<EnqueuedTask>
Typo tolerance
client.index('myIndex').getTypoTolerance(): Promise<TypoTolerance>
client.index('myIndex').updateTypoTolerance(typoTolerance: TypoTolerance | null): Promise<EnqueuedTask>
client.index('myIndex').resetTypoTolerance(): Promise<EnqueuedTask>
Separator tokens
client.index('myIndex').getSeparatorTokens(): Promise<SeparatorTokens>
client.index('myIndex').updateSeparatorTokens(separatorTokens: SeparatorTokens | null): Promise<EnqueuedTask>
client.index('myIndex').resetSeparatorTokens(): Promise<EnqueuedTask>
Non Separator tokens
client.index('myIndex').getNonSeparatorTokens(): Promise<NonSeparatorTokens>
client.index('myIndex').updateNonSeparatorTokens(nonSeparatorTokens: NonSeparatorTokens | null): Promise<EnqueuedTask>
client.index('myIndex').resetNonSeparatorTokens(): Promise<EnqueuedTask>
Dictionary
client.index('myIndex').getDictionary(): Promise<Dictionary>
client.index('myIndex').updateDictionary(dictionary: Dictionary | null): Promise<EnqueuedTask>
client.index('myIndex').resetDictionary(): Promise<EnqueuedTask>
Proximity Precision
client.index('myIndex').getProximityPrecision(): Promise<ProximityPrecision>
client.index('myIndex').updateProximityPrecision(proximityPrecision: ProximityPrecision): Promise<EnqueuedTask>
client.index('myIndex').resetProximityPrecision(): Promise<EnqueuedTask>
Embedders
⚠️ This feature is experimental. Activate the vectorStore
experimental feature to use it
client.index('myIndex').getEmbedders(): Promise<Embedders>
client.index('myIndex').updateEmbedders(embedders: Embedders): Promise<EnqueuedTask>
client.index('myIndex').resetEmbedders(): Promise<EnqueuedTask>
SearchCutoffMs
client.index('myIndex').getSearchCutoffMs(): Promise<SearchCutoffMs>
client.index('myIndex').updateSearchCutoffMs(searchCutoffMs: SearchCutoffMs): Promise<EnqueuedTask>
client.index('myIndex').resetSearchCutoffMs(): Promise<EnqueuedTask>
Keys
client.getKeys(parameters: KeysQuery): Promise<KeysResults>
client.getKey(keyOrUid: string): Promise<Key>
client.createKey(options: KeyCreation): Promise<Key>
client.updateKey(keyOrUid: string, options: KeyUpdate): Promise<Key>
client.deleteKey(keyOrUid: string): Promise<void>
isHealthy
client.isHealthy(): Promise<boolean>
Health
client.health(): Promise<Health>
Stats
client.getStats(): Promise<Stats>
Version
client.getVersion(): Promise<Version>
Dumps
client.createDump(): Promise<EnqueuedTask>
Snapshots
client.createSnapshot(): Promise<EnqueuedTask>
Meilisearch provides and maintains many SDKs and integration tools like this one. We want to provide everyone with an amazing search experience for any kind of project. For a full overview of everything we create and maintain, take a look at the integration-guides repository.